/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - core/math/vector
// Copyright (c) 2014.  All Rights Reserved
//
// File:		AEVector3f.inl
// Author:		Gianluca Belardelli
// Date:		27/01/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AEVECTOR3F_INL_
#define _AEVECTOR3F_INL_

AE_FORCEINLINE void AEVector3f::Add( AEVector4fRefParam vcVector )
{
	SetAdd( *this, vcVector );
}

AE_FORCEINLINE void AEVector3f::Sub( AEVector4fRefParam vcVector )
{
	SetSub( *this, vcVector );
}

AE_FORCEINLINE void AEVector3f::Mul( AEVector4fRefParam vcVector )
{
	SetMul( *this, vcVector );
}

AE_FORCEINLINE void AEVector3f::Mul( AESimdFloat32ConstRef fValue )
{              
	SetMul( *this, fValue );
}

AE_FORCEINLINE void AEVector3f::AddMul( AEVector4fRefParam vcVector, AESimdFloat32ConstRef fValue )
{
	SetAddMul(*this, vcVector, fValue );
}

AE_FORCEINLINE void AEVector3f::AddMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector )
{
	SetAddMul(*this, vcVector, fValue );
}

AE_FORCEINLINE void AEVector3f::SubMul( AEVector4fRefParam vcVector, AESimdFloat32ConstRef fValue )
{
	SetSubMul(*this, vcVector, fValue );
}

AE_FORCEINLINE void AEVector3f::SetMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector )
{
	SetMul( vcVector, fValue );
}

AE_FORCEINLINE void AEVector3f::AddMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 )
{
	SetAddMul( *this, vcVector1, vcVector2 );
}

AE_FORCEINLINE void AEVector3f::SubMul( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 )
{
	SetSubMul(*this, vcVector1, vcVector2 );
}

AE_FORCEINLINE void AEVector3f::SubMul( AESimdFloat32ConstRef fValue, AEVector4fRefParam vcVector )
{
	SetSubMul(*this, vcVector, fValue );
}

template <int N> 
AE_FORCEINLINE void AEVector3f::SetHorizontalAdd( AEVector4fRefParam vcVector )
{
	SetAll( vcVector.HorizontalAdd<N>() );
}

template <int N> 
AE_FORCEINLINE void AEVector3f::SetHorizontalMax( AEVector4fRefParam vcVector )
{
	SetAll( vcVector.HorizontalMax<N>() );
}

template <int N> 
AE_FORCEINLINE void AEVector3f::SetHorizontalMin( AEVector4fRefParam vcVector )
{
	SetAll( vcVector.HorizontalMin<N>() );
}

template <int N>
AE_FORCEINLINE void AEVector3f::SetDot( AEVector4fRefParam vcVector1, AEVector4fRefParam vcVector2 )
{
	SetAll( vcVector1.Dot<N>( vcVector2 ) );
}

template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLength( void ) const
{
	const AESimdFloat32 len2 = LengthSquared<N>();
	return len2.Sqrt<A,S>();
}

template <int N>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLength( void ) const
{
	return Length<N, AE_ACC_23_BIT, AE_SQRT_SET_ZERO>();
}

template <int N>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLengthSquared( void ) const
{
	return GetDot<N>(*this);
}

template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S> 
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLengthInverse( void ) const
{
	const AESimdFloat32 len2 = GetLengthSquared<N>();
	return len2.GetSqrtInverse<A,S>();
}

template <int N>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLengthInverse( void ) const
{
	return GetLengthInverse<N, AE_ACC_23_BIT, AE_SQRT_SET_ZERO>();
}

template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S>
AE_FORCEINLINE void AEVector3f::Normalize( void )
{
	Mul( GetLengthInverse< N, A, S >() );
}

template <int N>
AE_FORCEINLINE void AEVector3f::Normalize( void )
{
	Normalize<N, AE_ACC_23_BIT, AE_SQRT_SET_ZERO>();
}

template <int N, AEMathAccuracyMode A, AEMathNegSqrtMode S>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLengthAndNormalize( void )
{
	const AESimdFloat32 len2 = GetLengthSquared<N>();
	const AESimdFloat32 lenInv = len2.SqrtInverse<A,S>();
	Mul(lenInv);
	return (len2 * lenInv);
}

template <int N>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetLengthAndNormalize( void )
{
	return LengthAndNormalize<N, AE_ACC_23_BIT, AE_SQRT_SET_ZERO>();
}

template <AEMathAccuracyMode A, AEMathNegSqrtMode S>
AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetDistanceTo( AEVector4fRefParam vcVector ) const
{
	const AESimdFloat32 d2 = GetDistanceToSquared( vcVector );
	const AESimdFloat32 ri = d2.SqrtInverse<A,S>();
	return (d2 * ri);
}

AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetDistanceTo( AEVector4fRefParam vcVector ) const
{
	return GetDistanceToSquared( vcVector ).Sqrt<AE_ACC_23_BIT, AE_SQRT_SET_ZERO>();
}

AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetDistanceToSquared( AEVector4fRefParam vcVector ) const
{
	AEVector3f d;
	d.SetSub( *this, vcVector );
	return d.GetLengthSquared<3>();
}

AE_FORCEINLINE void AEVector3f::SetW( AESimdFloat32ConstRef fW )
{
	SetComponent<3>( fW );
}

AE_FORCEINLINE void AEVector3f::operator= ( AEVector4fRefParam vcVector )
{
	m_qfVector = vcVector.m_qfVector;
}

AE_FORCEINLINE void AEVector3f::SetPlaneConstant( AEVector4fRefParam vcPointOnPlane )
{
	const AESimdFloat32 fW = GetDot<3>(vcPointOnPlane);
	SetW( -fW );
}

AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetX( void ) const
{
	return GetComponent<0>();
}

AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetY( void ) const
{
	return GetComponent<1>();
}

AE_FORCEINLINE const AESimdFloat32 AEVector3f::GetZ( void ) const
{
	return GetComponent<2>();
}















/*

// Helper macro to copy vector parameters into local variables
// This might look like stupid unnecessary code, but it helps the compiler to optimize the assembly code
#define AEVECTOR4_COPYTEMPS(var) \
  const float var##_x = var.fX; const float var##_y = var.fY; const float var##_z = var.fZ; const float var##_w = var.fW;

AE_FORCEINLINE void AEVector3f::SetZero( void )
{
	fX = 0.0f;
	fY = 0.0f;
	fZ = 0.0f;
	fW = 0.0f;
}

AE_FORCEINLINE void AEVector3f::Set( float _fX, float _fY, float _fZ, float _fW )
{
	fX = _fX;
	fY = _fY;
	fZ = _fZ;
	fW = _fW;
}

AE_FORCEINLINE void AEVector3f::Set( float fXYZW )
{
	fX = fXYZW;
	fY = fXYZW;
	fZ = fXYZW;
	fW = fXYZW;
}

AE_FORCEINLINE float AEVector3f::operator[] ( AEUINT32 uiIdx ) const
{
	AEASSERT( uiIdx <= 3 );

	return fData[uiIdx];
}

AE_FORCEINLINE float& AEVector3f::operator[] ( AEUINT32 uiIdx )
{
	AEASSERT( uiIdx <= 3 );

	return fData[uiIdx];
}

AE_FORCEINLINE const AEVector3f AEVector3f::operator- ( void ) const
{
	return AEVector3f( -fX, -fY, -fZ, -fW );
}

AE_FORCEINLINE void AEVector3f::operator+= ( const AEVector3f &vcRhs )
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	fX += vcRhs_x;
	fY += vcRhs_y;
	fZ += vcRhs_z;
	fW += vcRhs_w;
}

AE_FORCEINLINE void AEVector3f::operator-= ( const AEVector3f &vcRhs )
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	fX -= vcRhs_x;
	fY -= vcRhs_y;
	fZ -= vcRhs_z;
	fW -= vcRhs_w;
}

AE_FORCEINLINE void AEVector3f::operator+= ( float fValue )
{
	fX += fValue;
	fY += fValue;
	fZ += fValue;
	fW += fValue;
}

AE_FORCEINLINE void AEVector3f::operator-= ( float fValue )
{
	fX -= fValue;
	fY -= fValue;
	fZ -= fValue;
	fW -= fValue;
}

AE_FORCEINLINE void AEVector3f::operator*= ( float fValue )
{
	fX *= fValue;
	fY *= fValue;
	fZ *= fValue;
	fW *= fValue;
}

AE_FORCEINLINE void AEVector3f::operator/= ( float fValue )
{
	const float fTemp = 1.0f / fValue;

	fX *= fTemp;
	fY *= fTemp;
	fZ *= fTemp;
	fW *= fTemp;
}

AE_FORCEINLINE bool AEVector3f::IsZero( float fEpsilon ) const
{
	AEASSERT( fEpsilon >= 0.0f );

	if( fEpsilon == 0.0f )
		return ( ( fX == 0 ) && ( fY == 0 ) && ( fZ == 0 ) && ( fW == 0 ) );

	return ( ( fX >= -fEpsilon ) && ( fX <= fEpsilon ) &&
			 ( fY >= -fEpsilon ) && ( fY <= fEpsilon ) &&
			 ( fZ >= -fEpsilon ) && ( fZ <= fEpsilon ) &&
			 ( fW >= -fEpsilon ) && ( fW <= fEpsilon ) );
}

AE_FORCEINLINE bool AEVector3f::IsValid( void ) const
{
	return ( AEMath::IsFiniteNumber( fX ) && AEMath::IsFiniteNumber( fY ) && AEMath::IsFiniteNumber( fZ ) && AEMath::IsFiniteNumber( fW ) );
}

AE_FORCEINLINE bool AEVector3f::IsNormalized( float fEpsilon ) const
{
	AEASSERT( fEpsilon >= 0.0f );

	const float fLen = GetLengthSquared();

	return AEMath::IsFloatEqual( fLen, 1.0f, fEpsilon );
}

AE_FORCEINLINE bool AEVector3f::IsIdentical( const AEVector3f &vcRhs ) const
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	return ( ( fX == vcRhs_x ) && ( fY == vcRhs_y ) && ( fZ == vcRhs_z ) && ( fW == vcRhs_w ) );
}

AE_FORCEINLINE bool AEVector3f::IsEqual( const AEVector3f &vcRhs,  float fEpsilon ) const
{
	AEASSERT( fEpsilon >= 0.0f );

	AEVECTOR4_COPYTEMPS( vcRhs );

	return ( AEMath::IsFloatEqual( fX, vcRhs_x, fEpsilon ) &&
			 AEMath::IsFloatEqual( fY, vcRhs_y, fEpsilon ) &&
			 AEMath::IsFloatEqual( fZ, vcRhs_z, fEpsilon ) &&
			 AEMath::IsFloatEqual( fW, vcRhs_w, fEpsilon ) );
}

AE_FORCEINLINE float AEVector3f::GetLengthSquared( void ) const
{
	return ( ( fX * fX ) + ( fY * fY ) + ( fZ * fZ ) + ( fW * fW ) );
}

AE_FORCEINLINE float AEVector3f::GetLength( void ) const
{
	return AEMath::Sqrt( GetLengthSquared() );
}

AE_FORCEINLINE float AEVector3f::GetLengthAndNormalize( void )
{
	const float fLength = GetLength();
	operator*= ( 1.0f / fLength );

	return fLength;
}

AE_FORCEINLINE float AEVector3f::GetLengthInverse( void ) const
{
	return AEMath::SqrtInverse( GetLengthSquared() );
}

AE_FORCEINLINE const AEVector3f AEVector3f::GetNormalized( void ) const
{
	AEVector3f vcTemp( *this );
	vcTemp.Normalize();
	return vcTemp;
}

AE_FORCEINLINE void AEVector3f::Normalize( void )
{
	operator*= ( GetLengthInverse() );
}

AE_FORCEINLINE AERESULT AEVector3f::NormalizeIfNotZero( float fEpsilon )
{
	if( ( IsZero( fEpsilon ) ) || ( !IsValid() ) )
		return AE_FAILURE;

	Normalize();
	return AE_SUCCESS;
}

AE_FORCEINLINE float AEVector3f::NormalizedEnsureUnitLength( void )
{
	if( ( IsZero( AEMATH_EPSILON ) ) || ( !IsValid() ) )
	{
		Set( 1, 0, 0, 0 );
		return 0.0f;
	}

	const float fLen = GetLength();
	*this /= fLen;

	return fLen;
}

AE_FORCEINLINE float AEVector3f::GetDistanceTo( const AEVector3f &vcRhs ) const
{
	return ( vcRhs - *this ).GetLength();
}

AE_FORCEINLINE float AEVector3f::GetDistanceToSquared( const AEVector3f &vcRhs ) const
{
	return ( vcRhs - *this ).GetLengthSquared();
}

AE_FORCEINLINE AERESULT AEVector3f::SetLength( float fValue, float fEpsilon )
{
	const AERESULT aeRes = NormalizeIfNotZero( fEpsilon );
	operator*= ( fValue );

	return aeRes;
}

AE_FORCEINLINE void AEVector3f::SetMin( const AEVector3f &vcRhs )
{
	SetMin( *this, vcRhs );
}

AE_FORCEINLINE void AEVector3f::SetMax( const AEVector3f &vcRhs )
{
	SetMax( *this, vcRhs );
}

AE_FORCEINLINE void AEVector3f::ClampTo( const AEVector3f &vcMinVal, const AEVector3f &vcMaxVal )
{
	SetClamped( *this, vcMinVal, vcMaxVal );
}

AE_FORCEINLINE const AEVector3f AEVector3f::CompMul( const AEVector3f &vcRhs ) const
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	return AEVector3f( fX * vcRhs_x, fY * vcRhs_y, fZ * vcRhs_z, fW * vcRhs_w );
}

AE_FORCEINLINE const AEVector3f AEVector3f::CompDiv( const AEVector3f &vcRhs ) const
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	return AEVector3f( fX / vcRhs_x, fY / vcRhs_y, fZ / vcRhs_z, fW / vcRhs_w );
}

AE_FORCEINLINE void AEVector3f::SetMin( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	AEVECTOR4_COPYTEMPS( vcLhs );
	AEVECTOR4_COPYTEMPS( vcRhs );

	fX = AEMath::Min( vcLhs_x, vcRhs_x );
	fY = AEMath::Min( vcLhs_y, vcRhs_y );
	fZ = AEMath::Min( vcLhs_z, vcRhs_z );
	fW = AEMath::Min( vcLhs_w, vcRhs_w );
}

AE_FORCEINLINE void AEVector3f::SetMax( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	AEVECTOR4_COPYTEMPS( vcLhs );
	AEVECTOR4_COPYTEMPS( vcRhs );

	fX = AEMath::Max( vcLhs_x, vcRhs_x );
	fY = AEMath::Max( vcLhs_y, vcRhs_y );
	fZ = AEMath::Max( vcLhs_z, vcRhs_z );
	fW = AEMath::Max( vcLhs_w, vcRhs_w );
}

AE_FORCEINLINE void AEVector3f::SetClamped( const AEVector3f &vcVal, const AEVector3f &vcMinVal, const AEVector3f &vcMaxVal )
{
	AEVECTOR4_COPYTEMPS( vcVal );
	AEVECTOR4_COPYTEMPS( vcMinVal );
	AEVECTOR4_COPYTEMPS( vcMaxVal );

	fX = AEMath::Clamp( vcVal_x, vcMinVal_x, vcMaxVal_x );
	fY = AEMath::Clamp( vcVal_y, vcMinVal_y, vcMaxVal_y );
	fZ = AEMath::Clamp( vcVal_z, vcMinVal_z, vcMaxVal_z );
	fW = AEMath::Clamp( vcVal_w, vcMinVal_w, vcMaxVal_w );
}

AE_FORCEINLINE void AEVector3f::SetAbs( const AEVector3f &vcVal )
{
	AEVECTOR4_COPYTEMPS( vcVal );

	fX = AEMath::Abs( vcVal_x );
	fY = AEMath::Abs( vcVal_y );
	fZ = AEMath::Abs( vcVal_z );
	fW = AEMath::Abs( vcVal_w );
}

AE_FORCEINLINE void AEVector3f::SetInterpolate( const AEVector3f &vcLhs, const AEVector3f &vcRhs, float fFactor )
{
	AEVECTOR4_COPYTEMPS( vcLhs );
	AEVECTOR4_COPYTEMPS( vcRhs );

	fX = AEMath::Interpolate( vcLhs_x, vcRhs_x, fFactor );
	fY = AEMath::Interpolate( vcLhs_y, vcRhs_y, fFactor );
	fZ = AEMath::Interpolate( vcLhs_z, vcRhs_z, fFactor );
	fW = AEMath::Interpolate( vcLhs_w, vcRhs_w, fFactor );
}

AE_FORCEINLINE float AEVector3f::Dot( const AEVector3f &vcRhs ) const
{
	AEVECTOR4_COPYTEMPS( vcRhs );

	return ( ( fX * vcRhs_x ) + ( fY * vcRhs_y ) + ( fZ * vcRhs_z ) + ( fW * vcRhs_w ) );
}

AE_FORCEINLINE void AEVector3f::Negate( void )
{
	fX = -fX;
	fY = -fY;
	fZ = -fZ;
	fW = -fW;
}

AE_FORCEINLINE const AEVector2 AEVector3f::GetAsVec2( void ) const
{
	return AEVector2( fX, fY );
}

AE_FORCEINLINE const AEVector3 AEVector3f::GetAsVec3( void ) const
{
	return AEVector3( fX, fY, fZ );
}

AE_FORCEINLINE bool operator== ( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	return vcLhs.IsIdentical( vcRhs );
}

AE_FORCEINLINE bool operator!= ( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	return !vcLhs.IsIdentical( vcRhs );
}

AE_FORCEINLINE const AEVector3f operator+ ( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	AEVector3f vcTemp( vcLhs );
	vcTemp += vcRhs;
	return vcTemp;
}

AE_FORCEINLINE const AEVector3f operator- ( const AEVector3f &vcLhs, const AEVector3f &vcRhs )
{
	AEVector3f vcTemp( vcLhs );
	vcTemp -= vcRhs;
	return vcTemp;
}

AE_FORCEINLINE const AEVector3f operator* ( const AEVector3f &vcLhs,  float fValue )
{
	AEVector3f vcTemp( vcLhs );
	vcTemp *= fValue;
	return vcTemp;
}

AE_FORCEINLINE const AEVector3f operator* ( float fValue , const AEVector3f &vcRhs )
{
	AEVector3f vcTemp( vcRhs );
	vcTemp *= fValue;
	return vcTemp;
}

AE_FORCEINLINE const AEVector3f operator/ ( const AEVector3f &vcLhs,  float fValue )
{
	AEVector3f vcTemp( vcLhs );
	vcTemp /= fValue;
	return vcTemp;
}
*/
#endif
// _AEVECTOR4_INL_
